home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / amitcp / amitcp-src-22.lha / AmiTCP-2.2 / src / devs / agnet / device.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  35.0 KB  |  1,385 lines

  1. RCS_ID_C="$Id: device.c,v 2.3 1993/10/20 15:17:52 jraja Exp $";
  2. /*
  3.  * device.c --- SANA-II test device, device functions
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright (c) 1993 AmiTCP/IP Group,
  8.  *                    Helsinki University of Technology, Finland.
  9.  *                    All rights reserved.
  10.  *
  11.  * Created      : Thu Jan 21 17:32:55 1993 ppessi
  12.  * Last modified: Wed Oct 20 16:49:15 1993 jraja
  13.  *
  14.  * $Log: device.c,v $
  15.  * Revision 2.3  1993/10/20  15:17:52  jraja
  16.  * Added correct prototype for the CheckIO().
  17.  *
  18.  * Revision 2.2  1993/10/14  00:09:43  ppessi
  19.  * Changed RCS Id format
  20.  *
  21.  * Revision 2.1  93/05/14  16:48:21  ppessi
  22.  * Release version
  23.  * 
  24.  */
  25.  
  26. #include <string.h>
  27.  
  28. #include <dos/dostags.h>
  29. #include <dos/rdargs.h>
  30. #include <intuition/intuition.h>
  31. #include <rexx/storage.h>
  32. #include <rexx/rxslib.h>
  33.  
  34. #include <clib/alib_stdio_protos.h>
  35.  
  36. #ifdef __SASC
  37. #include <clib/exec_protos.h>
  38. #include <pragmas/exec_sysbase_pragmas.h>
  39. #include <clib/dos_protos.h>
  40. #include <pragmas/dos_pragmas.h>
  41. #include <clib/utility_protos.h>
  42. #include <pragmas/utility_pragmas.h>
  43. #include <clib/timer_protos.h>
  44. #include <pragmas/timer_pragmas.h>
  45. #endif
  46.  
  47. #ifdef __GNUC__
  48. #include <inline/exec.h>
  49. #include <inline/dos.h>
  50. #include <inline/utility.h>
  51. #include <inline/timer.h>
  52. #endif
  53.  
  54. #include "agnet.h"
  55. #include "agnet_protos.h"
  56. #include "agnet_rev.h"
  57. #include "bases.h"
  58.  
  59. /* Correct prototype for the CheckIO.
  60.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  61.  * instead of a pointer (32 bits)!)
  62.  */
  63. struct IORequest * CheckIO(struct IORequest *req);
  64.  
  65. /* Local prototypes */
  66. static ULONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2);
  67. static VOID CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  68. static VOID ExpungeUnit(struct AgnetDevUnit *adu);
  69. static VOID TermIO(struct IOSana2Req *ios2);
  70. static VOID GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  71. static VOID GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  72. static VOID GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  73. static VOID TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  74. static VOID UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  75. static VOID PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type);
  76. static VOID PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type);
  77. static VOID PacketOverrun(struct AgnetDevUnit *adu);
  78. static VOID ReceivedGarbage(struct AgnetDevUnit *adu);
  79. static VOID PacketDropped(struct AgnetDevUnit *adu, ULONG type);
  80. static VOID ReceivedOrphan(struct AgnetDevUnit *adu);
  81. static VOID ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  82. static VOID GetStationAddress(struct AgnetDevUnit *, struct IOSana2Req *);
  83. static VOID DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  84. static VOID Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  85. static VOID Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  86. static VOID OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  87. static VOID DoEvent(struct AgnetDevUnit *adu, ULONG event);
  88. static VOID WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  89. static VOID ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  90. static VOID ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2);
  91. static VOID SendPacket(struct DelayRequest *delayed);
  92. static VOID ReceivePacket(struct DelayRequest *delayed);
  93. static VOID DoReceive(struct AgnetDevUnit *, struct DelayRequest *delayed );
  94. static VOID CopyBack(struct AgnetDevUnit *, struct IOSana2Req *, 
  95.              struct DelayRequest *);
  96.  
  97. /*
  98.  * Device Open vector
  99.  *
  100.  * a1 - SANA2 IO Request
  101.  * a6 - Pointer to our device base
  102.  * d0 - Unit number
  103.  * d1 - Flags
  104.  */
  105. ULONG ASM 
  106. DevOpen(REG(a1) struct IOSana2Req *ios2,
  107.     REG(d0) ULONG s2unit,
  108.     REG(d1) ULONG s2flags)
  109. {
  110.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  111.   struct AgnetDevUnit *adu;
  112.   struct TagItem *bufftag;
  113.   struct Library *UtilityBase;
  114.   struct BufferManagement *bm;
  115.   BYTE status = IOERR_UNITBUSY;
  116.  
  117.   /* Make sure our open remains single-threaded.
  118.      We may Wait() when starting up. If somebody
  119.      decides to DoExpunge() before we get the
  120.      semaphore, system is probably blowing up anyways.
  121.      */
  122.   ObtainSemaphore(&AgnetDev->ad_Lock);
  123.  
  124.   /* So we won't expunge ourselves... */
  125.   AgnetDev->ad_Dev_OpenCnt++;
  126.  
  127.   if (s2unit < AD_MAXUNITS)       /* Legal Unit */
  128.     if (adu = InitUnit(s2unit))      /* Initialize the unit? */
  129.       if (UtilityBase = OpenLibrary("utility.library", 37L)) { /* For Tag functions */
  130.  
  131.     /* Allocate a structure to store the pointers to the callback routines. */
  132.     if (bm = AllocMem(sizeof(*bm), MEMF_CLEAR|MEMF_PUBLIC)) {
  133.       /* Note: I don't complain if I can't find pointers to the callback routines.
  134.          This is because there are some programs that may need to open me, but
  135.          will never use any device commands that require the callbacks. */
  136.       if (bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
  137.         bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
  138.       }
  139.       if (bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement)) {
  140.         bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
  141.       }
  142.       AddTail((struct List *)&adu->adu_BuffMgmt, (struct Node *)bm);
  143.  
  144.       /* Everything went okay. */
  145.       status = 0;
  146.       AgnetDev->ad_Dev_OpenCnt++;
  147.       AgnetDev->ad_Dev_Flags &= ~LIBF_DELEXP;
  148.       adu->adu_Unit_OpenCnt++;
  149.  
  150.       /* Fix up the initial io request */
  151.       ios2->ios2_BufferManagement = (VOID *)bm;
  152.       ios2->ios2_Req.io_Error = 0;
  153.       ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  154.       ios2->ios2_Req.io_Unit = adu;
  155.       ios2->ios2_Req.io_Device = AgnetDev;
  156.     }
  157.     CloseLibrary(UtilityBase);
  158.       }
  159.  
  160.   /* See if something went wrong. */
  161.   if (status) {
  162.     ios2->ios2_Req.io_Error = status;
  163.     ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  164.     ios2->ios2_Req.io_Device = (struct Device *) -1;
  165.   }
  166.   AgnetDev->ad_Dev_OpenCnt--;
  167.   ReleaseSemaphore(&AgnetDev->ad_Lock);
  168.  
  169.   return status;
  170. }
  171.  
  172. /*
  173.  * Device Close vector.
  174.  *
  175.  * a1 - IOReq
  176.  * a6 - Device Pointer
  177.  */
  178. BPTR ASM 
  179. DevClose(REG(a1) struct IOSana2Req *ios2)
  180. {
  181.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  182.   struct AgnetDevUnit *adu;
  183.   BPTR seglist = 0L;
  184.  
  185.   ObtainSemaphore(&AgnetDev->ad_Lock);
  186.  
  187.   adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  188.   CloseUnit(adu, ios2);
  189.  
  190.   /* Trash the io_Device and io_Unit fields so that any attempt to use this
  191.      request will die immediatly. */
  192.  
  193.   ios2->ios2_Req.io_Device = (struct Device *) -1;
  194.   ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  195.  
  196.   AgnetDev->ad_Dev_OpenCnt--;
  197.  
  198.   /* Check to see if we've been asked to expunge. */
  199.   if (AgnetDev->ad_Dev_OpenCnt == 0 && AgnetDev->ad_Dev_Flags & LIBF_DELEXP) {
  200.     Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
  201.   }
  202.   ReleaseSemaphore(&AgnetDev->ad_Lock);
  203.  
  204.   return seglist;
  205. }
  206.  
  207. /*
  208.  * Device Expunge vector
  209.  *
  210.  * a6 - Device base
  211.  *
  212.  * Note: You may NEVER EVER Wait() in expunge. Period.
  213.  *     Don't even *think* about it.
  214.  */
  215. BPTR ASM 
  216. DevExpunge(VOID)
  217. {
  218.   struct AgnetDevice *AgnetDev = AgnetDeviceBase;
  219.  
  220.   AgnetDev->ad_Dev_Flags |= LIBF_DELEXP;
  221.   Signal(AgnetDev->ad_Task, SIGBREAKF_CTRL_F);
  222.  
  223.   /* We can not expunge  */
  224.   return (BPTR)0L;
  225. }
  226.  
  227. /*
  228.  * Device Reserved vector (returns 0L)
  229.  */
  230. ULONG ASM 
  231. DevReserved(VOID)
  232. {
  233.   return 0L;
  234. }
  235.  
  236. /*
  237.  * BeginIO --- dispatch incoming requests
  238.  *
  239.  * a1 - The IO request
  240.  * a6 - The device base
  241.  */
  242. #define SLIP_IMMEDIATES 0L    /* No QUICK IO */
  243.  
  244. VOID ASM 
  245. DevBeginIO(REG(a1) struct IOSana2Req *ios2)
  246. {
  247.   register struct AgnetDevice *ad;
  248.   ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  249.  
  250.   if (ios2->ios2_Req.io_Command < S2_END) {
  251.     if ((ios2->ios2_Req.io_Flags & IOF_QUICK) &&
  252.     ((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)) {
  253.       PerformIO(ios2);
  254.     } else {
  255.       ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  256.       /* Send this to DEVICE Message Port */
  257.       ad = (struct AgnetDevice*)ios2->ios2_Req.io_Device;
  258.       PutMsg(&ad->ad_MsgPort, (struct Message *)ios2);
  259.     }
  260.   } else {
  261.     ios2->ios2_Req.io_Error = IOERR_NOCMD;
  262.     TermIO(ios2);
  263.   }
  264. }
  265.  
  266. /*
  267.  * The device AbortIO() entry point.
  268.  * 
  269.  * A1 - The IO request to be aborted.
  270.  * A6 - The device base.
  271.  */
  272. ULONG ASM 
  273. DevAbortIO(REG(a1) struct IOSana2Req *ios2)
  274. {
  275.   register struct AgnetDevUnit *adu = 
  276.     (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  277.   register ULONG result = 0L;
  278.  
  279.   
  280.   LockUnit(adu);
  281.   if (ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG) {
  282.     switch(ios2->ios2_Req.io_Command) {
  283.     case CMD_READ:    result = AbortReq(&adu->adu_Rx,ios2);
  284.       break;
  285.  
  286.     case CMD_WRITE:     result = AbortReq(&adu->adu_Tx,ios2);
  287.       break;
  288.  
  289.     case S2_READORPHAN:    result = AbortReq(&adu->adu_RxOrph,ios2);
  290.       break;
  291.  
  292.     case S2_ONEVENT:    result = AbortReq(&adu->adu_Events,ios2);
  293.       break;
  294.  
  295.     default:        result = IOERR_NOCMD;
  296.       break;
  297.     }
  298.   }
  299.   UnlockUnit(adu);
  300.   return result;
  301. }
  302.  
  303. /*
  304.  * This funcion is used to locate an IO request in a linked
  305.  * list and abort it if found.
  306.  */
  307. static ULONG 
  308. AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
  309. {
  310.   struct Node *node, *next;
  311.   ULONG result = IOERR_NOCMD;
  312.  
  313.   node = (struct Node *)minlist->mlh_Head;
  314.  
  315.   while (!TAILP(node)) {
  316.     next = node->ln_Succ;
  317.  
  318.     if (node == (struct Node *)ios2) {
  319.       Remove((struct Node *)ios2);
  320.       ios2->ios2_Req.io_Error = IOERR_ABORTED;
  321.       TermIO(ios2);
  322.       result = 0;
  323.     }
  324.     node = next;
  325.   }
  326.   return result;
  327. }
  328.  
  329. /*
  330.  * Real expunge
  331.  */
  332. BOOL 
  333. DoExpunge(struct AgnetDevice *adb)
  334. {
  335.   ULONG i;
  336.  
  337.   /* Well, if there is somebody trying to open,
  338.      they stuck with this */
  339.   ObtainSemaphore(&adb->ad_Lock);
  340.   if (adb->ad_Device.lib_OpenCnt != 0) {
  341.     ReleaseSemaphore(&adb->ad_Lock);
  342.     return FALSE;
  343.   }
  344.   Forbid();
  345.   Remove((struct Node *)adb);
  346.   Permit();
  347.  
  348.   /* Free up Units */
  349.   for (i=0; i < AD_MAXUNITS; i++) {
  350.     if (adb->ad_Units[i])
  351.       ExpungeUnit((struct AgnetDevUnit *)adb->ad_Units[i]);
  352.     adb->ad_Units[i] = NULL;
  353.   }
  354.  
  355.   return TRUE;
  356. }
  357.  
  358. /*
  359.  * InitUnit
  360.  *
  361.  * Initialize (if needed) a new agnet.device Unit
  362.  */
  363. struct AgnetDevUnit *
  364. InitUnit(ULONG s2unit)
  365. {
  366.   struct AgnetDevUnit *adu;
  367.   struct AgnetDevice *adb = AgnetDeviceBase;
  368.  
  369.   /* Check to see if the Unit is already up and running.  If
  370.      it is, just drop through.  If not, try to start it up. */
  371.   if (adu = (struct AgnetDevUnit *)adb->ad_Units[s2unit])
  372.     return adu;
  373.  
  374.   /* Allocate a new Unit structure */
  375.   adu = AllocMem(sizeof(*adu), MEMF_CLEAR|MEMF_PUBLIC);
  376.   if (!adu)
  377.     return NULL;
  378.  
  379.   /* Do some initialization on the Unit structure */
  380. #if 0
  381.   NewList(&adu->adu_Unit_MsgPort.mp_MsgList);
  382.   adu->adu_Unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
  383.   adu->adu_Unit_MsgPort.mp_Flags = PA_IGNORE;
  384.   adu->adu_Unit_MsgPort.mp_Node.ln_Name = AGNETDEVNAME;
  385. #endif
  386.   adu->adu_UnitNum = s2unit;
  387.   adu->adu_Device = (struct Device *) adb;
  388.  
  389.   /* Try to read in our configuration file */
  390.   if (!ReadConfig(adu)) {
  391.     FreeMem(adu, sizeof(*adu));
  392.     return NULL;
  393.   }
  394.  
  395.   /* Initialize our list semaphore */
  396.   InitSemaphore(&adu->adu_Lock);
  397.  
  398.   /* Initialize our linked lists. */
  399.   NewList((struct List *)&adu->adu_FreeToTx);
  400.   NewList((struct List *)&adu->adu_Rx);
  401.   NewList((struct List *)&adu->adu_RxOrph);
  402.   NewList((struct List *)&adu->adu_Tx);
  403.   NewList((struct List *)&adu->adu_Events);
  404.   NewList((struct List *)&adu->adu_Track);
  405.   NewList((struct List *)&adu->adu_BuffMgmt);
  406.  
  407.   /* Allocate memory buffers */
  408.   DoOnline(adu);
  409.  
  410.   /* Set up the Unit structure pointer in the device base */
  411.   adb->ad_Units[s2unit] = adu;
  412.  
  413.   return adu;
  414. }
  415.  
  416. /*
  417.  * CloseUnit
  418.  *
  419.  * This function closes unit and frees resources
  420.  * allocated for each opener.
  421.  */
  422. static VOID 
  423. CloseUnit(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  424. {
  425.   register struct BufferManagement *bm = ios2->ios2_BufferManagement;
  426.  
  427.   LockUnit(adu);
  428.  
  429.   if (bm) {
  430.     ios2->ios2_BufferManagement = NULL;
  431.     Remove((struct Node *)bm);
  432.     FreeMem(bm, sizeof(*bm));
  433.   }
  434.   adu->adu_Unit.unit_OpenCnt--;
  435.  
  436.   UnlockUnit(adu);
  437. }
  438.  
  439. /*
  440.  *  ExpungeUnit
  441.  *
  442.  *  This function is called from the DoExpunge routine.
  443.  *  The unit structure and all subsequent allocations are freed.
  444.  */
  445. static VOID 
  446. ExpungeUnit(struct AgnetDevUnit *adu)
  447. {
  448.   struct IOSana2Req *ios2;
  449.   struct SuperS2PTStats *sstats;
  450.   int i;
  451.   struct List *io_queues[5];
  452.  
  453.   /* Eliminate every queues */
  454.   LockUnit(adu);
  455.  
  456.   io_queues[0] = (struct List *)&adu->adu_Rx;
  457.   io_queues[1] = (struct List *)&adu->adu_Tx;
  458.   io_queues[2] = (struct List *)&adu->adu_RxOrph;
  459.   io_queues[3] = (struct List *)&adu->adu_Events;
  460.   io_queues[4] = NULL;
  461.  
  462.   for (i = 0; io_queues[i]; i++) {
  463.     while(ios2 = (struct IOSana2Req *)RemHead(io_queues[i])) {
  464.       ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  465.       ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  466.       TermIO(ios2);
  467.      }
  468.   }
  469.  
  470.   /* Tracking data was allocated by us */
  471.   while(sstats = (struct SuperS2PTStats*)
  472.     RemHead((struct List *)&adu->adu_Track)) {
  473.     FreeMem(sstats, sizeof(*sstats));
  474.   }
  475.  
  476.   DoOffline(adu);
  477.  
  478.   UnlockUnit(adu);
  479.  
  480.   FreeMem(adu, sizeof(*adu));
  481. }
  482.  
  483. /*
  484.  * This routine is used to dispatch an IO request either from BeginIO
  485.  * or from the Unit process.
  486.  */
  487. VOID 
  488. PerformIO(struct IOSana2Req *ios2)
  489. {
  490.   struct AgnetDevUnit *adu = (struct AgnetDevUnit *)ios2->ios2_Req.io_Unit;
  491.  
  492.   if (ios2->ios2_Req.io_Device == 
  493.       AgnetDeviceBase->ad_Timer.tr_node.io_Device) {
  494.     ReceivePacket(ios2);
  495.     return;
  496.   }
  497.  
  498.   ios2->ios2_Req.io_Error = 0;
  499.  
  500.   switch(ios2->ios2_Req.io_Command) {
  501.   case CMD_READ:              ReadPacket(adu,ios2);
  502.     break;
  503.  
  504.   case CMD_WRITE:             WritePacket(adu,ios2);
  505.     break;
  506.  
  507.   case S2_DEVICEQUERY:        DeviceQuery(adu,ios2);
  508.     break;
  509.  
  510.   case S2_GETSTATIONADDRESS:  GetStationAddress(adu,ios2);
  511.     break;
  512.  
  513.   case S2_CONFIGINTERFACE:    ConfigInterface(adu,ios2);
  514.     break;
  515. #if 0
  516.     /* Non-existing commands */
  517.   case S2_ADDSTATIONALIAS:
  518.   case S2_DELSTATIONALIAS:
  519. #endif
  520.   case S2_ADDMULTICASTADDRESS:
  521.   case S2_DELMULTICASTADDRESS:
  522.   case S2_MULTICAST:
  523.     ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  524.     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  525.     TermIO(ios2);
  526.     break;
  527.  
  528.   case S2_BROADCAST:        WritePacket(adu,ios2);
  529.     break;
  530.  
  531.   case S2_TRACKTYPE:        TrackType(adu,ios2);
  532.     break;
  533.  
  534.   case S2_UNTRACKTYPE:      UnTrackType(adu,ios2);
  535.     break;
  536.  
  537.   case S2_GETTYPESTATS:     GetTypeStats(adu,ios2);
  538.     break;
  539.  
  540.   case S2_GETSPECIALSTATS:  GetSpecialStats(adu,ios2);
  541.     break;
  542.  
  543.   case S2_GETGLOBALSTATS:   GetGlobalStats(adu,ios2);
  544.     break;
  545.  
  546.   case S2_ONEVENT:          OnEvent(adu,ios2);
  547.     break;
  548.  
  549.   case S2_READORPHAN:       ReadOrphan(adu,ios2);
  550.     break;
  551.  
  552.   case S2_ONLINE:           Online(adu,ios2);
  553.     break;
  554.  
  555.   case S2_OFFLINE:          Offline(adu,ios2);
  556.     break;
  557.  
  558.   default:
  559.     ios2->ios2_Req.io_Error = IOERR_NOCMD;
  560.     TermIO(ios2);
  561.     break;
  562.   }
  563. }
  564.  
  565. /*
  566.  * This function is used to return an IO request
  567.  * back to the sender.
  568.  */
  569. static VOID 
  570. TermIO(struct IOSana2Req *ios2)
  571. {
  572.   if (!(ios2->ios2_Req.io_Flags & IOF_QUICK))
  573.     ReplyMsg((struct Message *)ios2);
  574. }
  575.  
  576. /*
  577.  * This function returns any device specific statistics that
  578.  * we may have.
  579.  *
  580.  * Currently, there is none.
  581.  *
  582.  * Ethernet may require some
  583.  */
  584. static VOID 
  585. GetSpecialStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  586. {
  587.   struct Sana2SpecialStatHeader *stats;
  588.  
  589.   stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
  590.  
  591.   stats->RecordCountSupplied = 0;
  592.   TermIO(ios2);
  593. }
  594.  
  595. /*
  596.  * This function returns the global statistics for the
  597.  * slip device.
  598.  */
  599. static VOID 
  600. GetGlobalStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  601. {
  602.   struct Sana2DeviceStats *stats;
  603.  
  604.   if (stats = (struct Sana2DeviceStats *)ios2->ios2_StatData) {
  605.     stats->PacketsReceived    = adu->adu_Stats.PacketsReceived;
  606.     stats->PacketsSent        = adu->adu_Stats.PacketsSent;
  607.     stats->BadData        = adu->adu_Stats.BadData;
  608.     stats->Overruns        = adu->adu_Stats.Overruns;
  609.     stats->UnknownTypesReceived = adu->adu_Stats.UnknownTypesReceived;
  610.     stats->Reconfigurations    = adu->adu_Stats.Reconfigurations;
  611.     stats->LastStart.tv_secs    = adu->adu_Stats.LastStart.tv_secs;
  612.     stats->LastStart.tv_micro    = adu->adu_Stats.LastStart.tv_secs;
  613.   } else {
  614.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  615.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  616.   }
  617.   TermIO(ios2);
  618. }
  619.  
  620. /*
  621.  * This function returns statistics for a specific
  622.  * type of packet that is being tracked.
  623.  *
  624.  * Just to be thourough, I have arbitrarily picked
  625.  * the packet type for SLIP IP packets to be 2048, the
  626.  * same as that used for Ethernet.  This will at least
  627.  * allow you to track IP packets.
  628.  */
  629. static VOID
  630. GetTypeStats(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  631. {
  632.   struct Sana2PacketTypeStats *stats;
  633.   struct SuperS2PTStats *sstats;
  634.  
  635.   if (stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData) {
  636.     LockUnit(adu);
  637.  
  638.     sstats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  639.  
  640.     /* Find asked packet type from tracking list */
  641.     while (sstats->ss_Node.mln_Succ) {
  642.       if (ios2->ios2_PacketType == sstats->ss_PType) {
  643.     stats->PacketsSent     = sstats->ss_Stats.PacketsSent;
  644.     stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
  645.     stats->BytesSent       = sstats->ss_Stats.BytesSent;
  646.     stats->BytesReceived   = sstats->ss_Stats.BytesReceived;
  647.     stats->PacketsDropped  = sstats->ss_Stats.PacketsDropped;
  648.     break;
  649.       }
  650.       sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
  651.     }
  652.     UnlockUnit(adu);
  653.     if (!sstats->ss_Node.mln_Succ) {
  654.       ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  655.       ios2->ios2_WireError    = S2WERR_NOT_TRACKED;
  656.     }
  657.   } else {
  658.     ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
  659.     ios2->ios2_WireError = S2WERR_NULL_POINTER;
  660.   }
  661.   TermIO(ios2);
  662. }
  663.  
  664. /*
  665.  * This function adds a packet type to the list
  666.  * of those that are being tracked.
  667.  */
  668. static VOID 
  669. TrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  670. {
  671.   struct SuperS2PTStats *stats;
  672.   ULONG type = ios2->ios2_PacketType;
  673.  
  674.   LockUnit(adu);
  675.  
  676.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  677.  
  678.   while (stats->ss_Node.mln_Succ) {
  679.     if (type == stats->ss_PType) {
  680.       ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  681.       ios2->ios2_WireError    = S2WERR_ALREADY_TRACKED;
  682.     }
  683.     stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  684.   }
  685.   if (!stats->ss_Node.mln_Succ) {
  686.     if(stats = AllocMem(sizeof(*stats), MEMF_CLEAR|MEMF_PUBLIC)) {
  687.       stats->ss_PType = type;
  688.       AddTail((struct List *)&adu->adu_Track, (struct Node *)stats);
  689.     }
  690.   }
  691.   UnlockUnit(adu);
  692.  
  693.   TermIO(ios2);
  694. }
  695.  
  696. /*
  697.  * This function removes a packet type from the
  698.  * list of those that are being tracked.
  699.  */
  700. static VOID 
  701. UnTrackType(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  702. {
  703.   struct SuperS2PTStats *stats;
  704.  
  705.   LockUnit(adu);
  706.  
  707.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  708.  
  709.   while (stats->ss_Node.mln_Succ) {
  710.     if (ios2->ios2_PacketType == stats->ss_PType) {
  711.       Remove((struct Node *)stats);
  712.       FreeMem(stats, sizeof(*stats));
  713.       stats = NULL;
  714.       break;
  715.     }
  716.     stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  717.   }
  718.   if(stats) {
  719.     ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  720.     ios2->ios2_WireError    = S2WERR_NOT_TRACKED;
  721.   }
  722.   UnlockUnit(adu);
  723.  
  724.   TermIO(ios2);
  725. }
  726.  
  727. /*
  728.  * This function is called whenever a packet is received
  729.  */
  730. static VOID 
  731. PacketReceived(struct AgnetDevUnit *adu, ULONG length, ULONG type)
  732. {
  733.   struct SuperS2PTStats *stats;
  734.  
  735.   adu->adu_Stats.PacketsReceived++;
  736.  
  737.   LockUnit(adu);
  738.  
  739.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  740.  
  741.   while (stats->ss_Node.mln_Succ) {
  742.     if (stats -> ss_PType == type) {
  743.       stats -> ss_Stats.PacketsReceived++;
  744.       stats -> ss_Stats.BytesReceived += length;
  745.       break;
  746.     }
  747.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  748.   }
  749.  
  750.   UnlockUnit(adu);
  751. }
  752.  
  753. /*
  754.  * This function is called whenever a packet is sent
  755.  */
  756. static VOID 
  757. PacketSent(struct AgnetDevUnit *adu, ULONG length, ULONG type)
  758. {
  759.   struct SuperS2PTStats *stats;
  760.  
  761.   adu->adu_Stats.PacketsSent++;
  762.  
  763.   LockUnit(adu);
  764.  
  765.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  766.  
  767.   while (stats->ss_Node.mln_Succ) {
  768.     if (stats -> ss_PType == type) {
  769.       stats -> ss_Stats.PacketsSent++;
  770.       stats -> ss_Stats.BytesSent += length;
  771.       break;
  772.     }
  773.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  774.   }
  775.  
  776.   UnlockUnit(adu);
  777. }
  778.  
  779. /*
  780.  * This function is called a packet overruns
  781.  */
  782. static VOID 
  783. PacketOverrun(struct AgnetDevUnit *adu)
  784. {
  785.   adu->adu_Stats.Overruns++;
  786.   DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
  787. }
  788.  
  789. /*
  790.  * This function is called whenever a packet with
  791.  * garbage data is encountered.
  792.  */
  793. static VOID 
  794. ReceivedGarbage(struct AgnetDevUnit *adu)
  795. {
  796.   adu->adu_Stats.BadData++;
  797.   DoEvent(adu, S2EVENT_HARDWARE | S2EVENT_RX | S2EVENT_ERROR);
  798. }
  799.  
  800. /*
  801.  * This function is called whenever a packet
  802.  * is dropped by the SLIP driver.
  803.  */
  804. static VOID 
  805. PacketDropped(struct AgnetDevUnit *adu, ULONG type)
  806. {
  807.   struct SuperS2PTStats *stats;
  808.  
  809.   LockUnit(adu);
  810.  
  811.   stats = (struct SuperS2PTStats *)adu->adu_Track.mlh_Head;
  812.  
  813.   while (stats->ss_Node.mln_Succ) {
  814.     if (stats -> ss_PType == type) {
  815.       stats -> ss_Stats.PacketsDropped++;
  816.       break;
  817.     }
  818.     stats = (struct SuperS2PTStats *)stats -> ss_Node.mln_Succ;
  819.   }
  820.  
  821.   UnlockUnit(adu);
  822. }
  823.  
  824. /*
  825.  * This function is called whenever an orphan packet
  826.  * is received
  827.  */
  828. static VOID 
  829. ReceivedOrphan(struct AgnetDevUnit *adu)
  830. {
  831.   adu->adu_Stats.UnknownTypesReceived++;
  832. }
  833.  
  834. /*
  835.  * This function handles S2_CONFIGINTERFACE commands.
  836.  */
  837. static VOID 
  838. ConfigInterface(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  839. {
  840.   /* Note: we may only be configured once. */
  841.   if (!(adu->adu_State & AGUF_CONFIG)) {
  842.     switch (adu->adu_HardwareType) {
  843.     case S2WireType_PPP:
  844.     case S2WireType_SLIP:
  845.     case S2WireType_CSLIP:
  846.     case S2WireType_Ethernet:
  847.     case S2WireType_IEEE802:
  848.     case S2WireType_Arcnet:
  849.     case S2WireType_LocalTalk:
  850.     case S2WireType_AmokNet:
  851.       /* Copy given address as our Station Address */
  852.       memcpy(&adu->adu_Addr, &ios2->ios2_SrcAddr, MAX_ADDR_BYTES);
  853.       /*FALLTHROUGH*/
  854.     default:
  855.       adu->adu_State |= AGUF_CONFIG;
  856.     }
  857.   } else {
  858.     /* Sorry, we're already configured. */
  859.     ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  860.     ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  861.   }
  862.   TermIO(ios2);
  863. }
  864.  
  865. /*
  866.  * This function handles S2_GETSTATIONADDRESS commands.
  867.  */
  868. static VOID 
  869. GetStationAddress(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  870. {
  871.   memcpy(ios2->ios2_DstAddr, adu->adu_Addr, MAX_ADDR_BYTES);
  872.   if (adu->adu_State & AGUF_CONFIG)
  873.     memcpy(ios2->ios2_SrcAddr, adu->adu_Addr, MAX_ADDR_BYTES);
  874.   else 
  875.     memset(ios2->ios2_SrcAddr, 0xff, MAX_ADDR_BYTES);
  876.   TermIO(ios2);
  877. }
  878.  
  879. /*
  880.  * This function handles S2_DEVICEQUERY comands.
  881.  */
  882. static VOID 
  883. DeviceQuery(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  884. {
  885.   struct Sana2DeviceQuery *sdq;
  886.  
  887.   sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
  888.  
  889.   sdq->DeviceLevel   = 0L;
  890.   sdq->AddrFieldSize = adu->adu_AddrFieldSize;
  891.   sdq->MTU           = adu->adu_MaxTU;
  892.   sdq->BPS           = adu->adu_BPS;
  893.   sdq->HardwareType  = adu->adu_HardwareType;
  894.  
  895.   sdq->SizeSupplied = sizeof(*sdq);
  896.   TermIO(ios2);
  897. }
  898.  
  899. /*
  900.  * This routime handles CMD_ONLINE commands.
  901.  */
  902. static VOID 
  903. Online(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  904. {
  905.   if (!(adu->adu_State & AGUF_ONLINE)) {
  906.     /* We're offline. Go online. */
  907.     LockUnit(adu);
  908.     if (DoOnline(adu)) {
  909.       /* Couldn't get online */
  910.       ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  911.       ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  912.     } 
  913.     UnlockUnit(adu);
  914.   }
  915.   TermIO(ios2);
  916. }
  917.  
  918. /* 
  919.  * Actual Online, return 0 on success
  920.  *
  921.  * Caller should have a lock on the unit
  922.  */
  923. LONG
  924. DoOnline(struct AgnetDevUnit *adu)
  925. {
  926.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  927.   ULONG mtu; LONG i; BOOL error = TRUE;
  928.   struct DelayRequest *txed;
  929.  
  930.   /* Allocate transfer buffer */
  931.   mtu = adu->adu_MaxTU + 64;
  932.   for (i = 0; i < MAX_TXED; i++) {
  933.     if (adu->adu_TxEd[i]) {
  934.       error = FALSE;
  935.       continue;
  936.     }
  937.     if (!(txed = CreateIORequest(&adb->ad_MsgPort, 
  938.                  sizeof(struct DelayRequest) + mtu))) 
  939.       break;
  940.     error = FALSE;
  941.     adu->adu_TxEd[i] = txed;
  942.     txed->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  943.     txed->tr_node.io_Device = adb->ad_Timer.tr_node.io_Device;
  944.     txed->tr_node.io_Unit = adb->ad_Timer.tr_node.io_Unit;
  945.     txed->tr_node.io_Command = TR_ADDREQUEST;
  946.     txed->dr_Unit = adu;
  947.     txed->dr_Len = mtu;
  948.     AddHead(&adu->adu_FreeToTx, txed);
  949.   }
  950.  
  951.   if (!error) {
  952.     adu->adu_State |= AGUF_ONLINE;
  953.     GetSysTime(&adu->adu_Stats.LastStart);
  954.     /* In case someone wants to know...*/
  955.     DoEvent(adu, S2EVENT_ONLINE);
  956.   }
  957.   return error;
  958. }
  959.  
  960. /*
  961.  * This routine handles CMD_OFFLINE commands.
  962.  * Any pending read or write request will be sent to 
  963.  * their owners
  964.  */
  965. static VOID 
  966. Offline(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  967. {
  968.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  969.  
  970.   if (adu->adu_State & AGUF_ONLINE) {
  971.     /* We're online, so shut everything down. */
  972.     LockUnit(adu);
  973.     DoOffline(adu);
  974.     UnlockUnit(adu);
  975.   }
  976.  
  977.   TermIO(ios2);
  978. }
  979.  
  980. /*
  981.  * Put the unit offline 
  982.  *
  983.  * Caller should have a lock on the unit
  984.  */
  985. VOID
  986. DoOffline(struct AgnetDevUnit *adu)
  987. {
  988.   struct AgnetDevice *adb = (struct AgnetDevice *)adu->adu_Device;
  989.   struct IOSana2Req *ios2;
  990.   int i;
  991.   struct DelayRequest *txed;
  992.  
  993.   adu->adu_State &= ~AGUF_ONLINE;
  994.  
  995.   while(ios2 = (struct IOSana2Req *)
  996.     RemHead((struct List *)&adu->adu_Rx)) {
  997.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  998.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  999.     TermIO(ios2);
  1000.   }
  1001.  
  1002.   while(ios2 = (struct IOSana2Req *)
  1003.     RemHead((struct List *)&adu->adu_RxOrph)) {
  1004.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1005.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1006.     TermIO(ios2);
  1007.   }
  1008.  
  1009.   while(ios2 = (struct IOSana2Req *)
  1010.     RemHead((struct List *)&adu->adu_Tx)) {
  1011.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1012.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1013.     TermIO(ios2);
  1014.   }
  1015.  
  1016.   /* 
  1017.    * Abort still pending delayrequests, 
  1018.    * free all delayrequests
  1019.    */
  1020.   for (i = MAX_TXED - 1; i >= 0; i--) {
  1021.     if (txed = adu->adu_TxEd[i]) {
  1022.       if (!CheckIO(txed))
  1023.     AbortIO(txed);
  1024.       WaitIO(txed);        /* also removes from free queue */
  1025.       DeleteIORequest(txed);
  1026.     }
  1027.     adu->adu_TxEd[i] = NULL;
  1028.   }
  1029.   
  1030.   DoEvent(adu, S2EVENT_OFFLINE);
  1031. }
  1032. /* 
  1033.  * This routine handles S2_ONEVENT commands 
  1034.  */
  1035. static VOID 
  1036. OnEvent(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1037. {
  1038.   /* Two special cases.
  1039.    *  If we are (on/off)line, and ask (on/off)line event,
  1040.    *  we return immediately 
  1041.    */
  1042.   if (ios2->ios2_WireError == S2EVENT_ONLINE &&
  1043.       adu->adu_State & AGUF_ONLINE ||
  1044.       ios2->ios2_WireError == S2EVENT_OFFLINE &&
  1045.       !(adu->adu_State & AGUF_ONLINE)) {
  1046.     TermIO(ios2);
  1047.   } else {
  1048.     LockUnit(adu);
  1049.     AddTail((struct List *)&adu->adu_Events, (struct Node *)ios2);
  1050.     UnlockUnit(adu);
  1051.   }
  1052. }
  1053.  
  1054. /*
  1055.  * This routine is called whenever an "important"
  1056.  * SANA-II event occurs.
  1057.  */
  1058. static VOID 
  1059. DoEvent(struct AgnetDevUnit *adu, ULONG event)
  1060. {
  1061.   struct IOSana2Req *ios2;
  1062.   struct IOSana2Req *ios2_next;
  1063.  
  1064.   LockUnit(adu);
  1065.  
  1066.   ios2 = (struct IOSana2Req *)adu->adu_Events.mlh_Head;
  1067.  
  1068.   while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ) {
  1069.     ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
  1070.  
  1071.     /* Is this the event they are looking for? */
  1072.     if(ios2->ios2_WireError & event) {
  1073.       Remove((struct Node *)ios2);
  1074.       ios2->ios2_WireError = event;
  1075.       TermIO(ios2);
  1076.     }
  1077.     ios2 = ios2_next;
  1078.   }
  1079.  
  1080.   UnlockUnit(adu);
  1081. }
  1082.  
  1083. /*
  1084.  * This function is used for handling CMD_WRITE and S2_BROADCAST
  1085.  * commands.
  1086.  */
  1087. static VOID 
  1088. WritePacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1089. {
  1090.   /* Make sure that we are online. */
  1091.   if (!(adu->adu_State & AGUF_ONLINE)) {
  1092.     /* Sorry, we're offline */
  1093.     ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1094.     ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1095.     TermIO(ios2);
  1096.     return;
  1097.   }
  1098.  
  1099.   /* Is the data length legal? */
  1100.   if (ios2->ios2_DataLength < adu->adu_MinTU ||
  1101.       ios2->ios2_DataLength > adu->adu_MaxTU) {
  1102.     /* Sorry, the packet is too long or too small! */
  1103.     ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
  1104.     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  1105.     TermIO(ios2);
  1106.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_ERROR);
  1107.     return;
  1108.   }
  1109.  
  1110.   /* We call the SendPacket if no delay */
  1111.   ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  1112.  
  1113.   {
  1114.     struct DelayRequest *delayed;
  1115.     LockUnit(adu);
  1116.     AddTail((struct List *)&adu->adu_Tx,(struct Node *)ios2);
  1117.     /* 
  1118.      * If there is free delay requests, 
  1119.      * try to send immediately
  1120.      */
  1121.     delayed = (struct DelayRequest *)
  1122.       RemHead((struct List *)&adu->adu_FreeToTx);
  1123.     UnlockUnit(adu);
  1124.  
  1125.     if (delayed)
  1126.       SendPacket(delayed);
  1127.   }
  1128.   return;
  1129. }
  1130.  
  1131. /*
  1132.  * This routine handles CMD_READ commands.  We
  1133.  * always queue these unless we're offline.
  1134.  */
  1135. static VOID 
  1136. ReadPacket(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1137. {
  1138.   if(adu->adu_State & AGUF_ONLINE) {
  1139.     /* Queue it... */
  1140.     LockUnit(adu);
  1141.     AddTail((struct List *)&adu->adu_Rx, (struct Node *)ios2);
  1142.     UnlockUnit(adu);
  1143.     return;
  1144.   }
  1145.  
  1146.   /* Sorry, we're offline */
  1147.   ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1148.   ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1149.   TermIO(ios2);
  1150. }
  1151.  
  1152. /*
  1153.  * This routine handles CMD_READORPHAN commands.  We
  1154.  * always queue these unless we're offline.
  1155.  */
  1156. static VOID
  1157. ReadOrphan(struct AgnetDevUnit *adu, struct IOSana2Req *ios2)
  1158. {
  1159.   if(adu->adu_State & AGUF_ONLINE) {
  1160.     /* Queue it... */
  1161.     LockUnit(adu);
  1162.     AddTail((struct List *)&adu->adu_RxOrph, (struct Node *)ios2);
  1163.     UnlockUnit(adu);
  1164.     return;
  1165.   }
  1166.  
  1167.   /* Sorry, we're offline */
  1168.   ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1169.   ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1170.   TermIO(ios2);
  1171. }
  1172.  
  1173. /*
  1174.  * "Send" next queued packet 
  1175.  */
  1176. static VOID
  1177. SendPacket(struct DelayRequest *delayed)
  1178. {
  1179.   struct AgnetDevUnit *adu = delayed->dr_Unit;
  1180.   struct BufferManagement *bm;
  1181.   struct IOSana2Req *ios2 = NULL;
  1182.   LONG length; ULONG delay;
  1183.  
  1184.   LockUnit(adu);
  1185.  
  1186.   while (!ios2) {
  1187.     ios2 = (struct IOSana2Req *)RemHead((struct List *)&adu->adu_Tx);
  1188.     /* There is nothing to send */
  1189.     if (!ios2) {
  1190.       AddHead((struct List *)&adu->adu_FreeToTx,(struct Node *)delayed);
  1191.       UnlockUnit(adu);
  1192.       return;
  1193.     }
  1194.  
  1195.     length = ios2->ios2_DataLength;
  1196.  
  1197.     /* Update statistics */
  1198.     PacketSent(adu, length, ios2->ios2_PacketType);
  1199.  
  1200.     /* Should we lose the packet? */
  1201.     if (adu->adu_Loss && adu->adu_Loss > LRandom() % LOSS_MAX) {
  1202.       TermIO(ios2);
  1203.       ios2 = NULL;
  1204.     }
  1205.   }
  1206.   UnlockUnit(adu);
  1207.  
  1208.   if (length > delayed->dr_Len)
  1209.     length = delayed->dr_Len;
  1210.  
  1211.   bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
  1212.  
  1213.   /* Copy the data out of the packet into timer request buffer. */
  1214.   if (bm->bm_CopyFromBuffer &&          
  1215.       (*bm->bm_CopyFromBuffer)    /* we should have this tag, really */
  1216.       (delayed->dr_Data, ios2->ios2_Data, length)) {
  1217.     delayed->dr_DataLen = length;
  1218.     /* Copy addresses */
  1219.     if ((delayed->dr_PPUnit = adu->adu_PPUnit) < 0) {
  1220.       WORD adrlen = adu->adu_AddrFieldSize + 7 >> 3;
  1221.       memcpy(delayed->dr_DstAddr, ios2->ios2_DstAddr, adrlen);
  1222.       memcpy(delayed->dr_SrcAddr, adu->adu_Addr, adrlen);
  1223.     }
  1224.     /* Set hwtype */
  1225.     delayed->dr_HardwareType = adu->adu_HardwareType;
  1226.     delayed->dr_PacketType = ios2->ios2_PacketType;
  1227.     /* We should recognize broadcasts or multicasts */
  1228.     delayed->dr_Cmd = ios2->ios2_Req.io_Command;
  1229.     /*  Make errors */
  1230.     if (adu->adu_Errors) {
  1231.       LONG total = adu->adu_Errors * length * 8 / (LRandom() % ERRORS_MAX);
  1232.       while (total-- > 0) {
  1233.       /* Make a bit error.. */
  1234.     ULONG position = LRandom() & 0x7fffffffL;
  1235.     /* flip a bit */
  1236.     delayed->dr_Data[(position / 8) % length] ^= 1 << (position % 8);
  1237.       }
  1238.     }
  1239.  
  1240.     /* calculate delay */
  1241.     delay = adu->adu_Delay;
  1242.     if (delay && adu->adu_Deviation) 
  1243.       delay = RandomDev(delay, adu->adu_Deviation);
  1244.  
  1245.     if (delay) {
  1246.       delayed->tr_node.io_Command = TR_ADDREQUEST;
  1247.       delayed->tr_time.tv_secs = delay / 1000;
  1248.       delayed->tr_time.tv_micro = (delay % 1000) * 1000;
  1249.       SendIO(delayed);
  1250.     } else {
  1251.       /* Fallthrough */
  1252.       ReceivePacket(delayed);
  1253.     }
  1254.   } else {
  1255.     /* Something went wrong...*/
  1256.     ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  1257.     ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  1258.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_TX | S2EVENT_BUFF | S2EVENT_ERROR);
  1259.   }
  1260.  
  1261.   TermIO(ios2);
  1262. }
  1263.  
  1264. /*
  1265.  * This routine is called whenever a packet is received.
  1266.  * It return all appropriate read requests
  1267.  */
  1268. static VOID
  1269. ReceivePacket(struct DelayRequest *delayed)
  1270. {
  1271.   struct AgnetDevUnit *adu;
  1272.   int i; 
  1273.  
  1274.   if (delayed->dr_PPUnit >= 0 && delayed->dr_PPUnit < AD_MAXUNITS) {
  1275.     adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[delayed->dr_PPUnit];
  1276.     if (adu)
  1277.       DoReceive(adu, delayed);
  1278.   } else {
  1279.     for (i = 0; i < AD_MAXUNITS; i++) {
  1280.       if (!(adu = (struct AgnetDevUnit *)AgnetDeviceBase->ad_Units[i]))
  1281.     continue;            /* No unit */
  1282.       if (delayed->dr_HardwareType != adu->adu_HardwareType) 
  1283.     continue;            /* Different hardware */
  1284.       if (delayed->dr_Cmd != S2_BROADCAST &&
  1285.       memcmp(delayed->dr_DstAddr, adu->adu_Addr, 
  1286.          adu->adu_AddrFieldSize + 7 >> 3)) 
  1287.     continue;            /* Address mismatched */
  1288.       DoReceive(adu, delayed);
  1289.     }
  1290.   } 
  1291.  
  1292.   SendPacket(delayed);
  1293. }
  1294.  
  1295. /* 
  1296.  * DoReceive
  1297.  */
  1298. static VOID 
  1299. DoReceive(struct AgnetDevUnit *adu, struct DelayRequest *delayed)
  1300. {
  1301.   ULONG length = delayed->dr_DataLen;
  1302.   ULONG type   = delayed->dr_PacketType;
  1303.   struct IOSana2Req *rxr;
  1304.  
  1305.   /* Update statistics */
  1306.   PacketReceived(adu, length, type);
  1307.   if (adu->adu_MaxTU < length) {
  1308.     PacketOverrun(adu);
  1309.     return;
  1310.   }
  1311.   if (adu->adu_MinTU > length) {
  1312.     ReceivedGarbage(adu);
  1313.     return;
  1314.   }
  1315.  
  1316.   /* Find an appropriate request wanting this packet type */
  1317.   LockUnit(adu);
  1318.  
  1319.   for (rxr = (struct IOSana2Req *)adu->adu_Rx.mlh_Head;
  1320.        rxr->ios2_Req.io_Message.mn_Node.ln_Succ; 
  1321.        rxr = (struct IOSana2Req *)rxr->ios2_Req.io_Message.mn_Node.ln_Succ) {
  1322.     if (rxr->ios2_PacketType == type) {
  1323.       Remove((struct Node *)rxr);
  1324.       CopyBack(adu, rxr, delayed);
  1325.       rxr = NULL;
  1326.       break;
  1327.     }
  1328.   }
  1329.  
  1330.   if (rxr) {
  1331.     /* Nobody wants this packet type? So, it's orphan */
  1332.     ReceivedOrphan(adu);
  1333.     if (rxr = (struct IOSana2Req *)
  1334.     RemHead((struct List *)&adu->adu_RxOrph)) {
  1335.       rxr -> ios2_PacketType = type;
  1336.       CopyBack(adu, rxr, delayed);
  1337.     } else {
  1338.       /* Nobody is interested in this packet, drop it */
  1339.       PacketDropped(adu, type);
  1340.     }
  1341.   }
  1342.   
  1343.   UnlockUnit(adu);
  1344. }
  1345.  
  1346. /*
  1347.  * Copy received packet into a request,
  1348.  * return the request to the caller
  1349.  */
  1350. static VOID
  1351. CopyBack(struct AgnetDevUnit *adu, struct IOSana2Req *ios2, 
  1352.      struct DelayRequest *delayed)
  1353. {
  1354.   struct BufferManagement * bm =
  1355.     (struct BufferManagement *)ios2->ios2_BufferManagement;
  1356.   void *data = delayed->dr_Data;
  1357.   ULONG length = delayed->dr_DataLen;
  1358.   WORD  adrlen = (adu->adu_AddrFieldSize + 7) >> 3;
  1359.  
  1360.   /* Copy the data into the protocol stack's buffer using its
  1361.      supplied callback routine. */
  1362.   if (bm->bm_CopyToBuffer &&
  1363.       (*bm->bm_CopyToBuffer)(ios2->ios2_Data, data, length)) {
  1364.     ios2->ios2_DataLength =    length;
  1365.  
  1366.     if (delayed->dr_Cmd == S2_BROADCAST) {
  1367.       ios2->ios2_Req.io_Flags |= SANA2IOB_BCAST;
  1368.       memset(ios2->ios2_DstAddr, 0xff, adrlen);
  1369.     } else {
  1370.       memcpy(ios2->ios2_DstAddr, adu->adu_Addr, adrlen);
  1371.     }
  1372.     memcpy(ios2->ios2_SrcAddr, delayed->dr_SrcAddr, adrlen); 
  1373.  
  1374.     return TermIO(ios2);
  1375.   } else {
  1376.     ios2->ios2_DataLength   = 0;
  1377.     ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  1378.     ios2->ios2_WireError    = S2WERR_BUFF_ERROR;
  1379.     DoEvent(adu, S2EVENT_SOFTWARE | S2EVENT_RX | S2EVENT_BUFF | S2EVENT_ERROR);
  1380.     return TermIO(ios2);
  1381.   }
  1382. }
  1383.  
  1384.  
  1385.